package com.anti.modular.sys.file.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.Log;
import com.anti.commom.constant.SymbolConstant;
import com.anti.commom.context.requestno.RequestNoContext;
import com.anti.commom.core.exception.BusinessException;
import com.anti.commom.core.utils.LibreOfficeUtil;
import com.anti.commom.file.FileOperators;
import com.anti.commom.file.exp.LibreOfficeException;
import com.anti.jdbc.DBUtils;
import com.anti.jdbc.support.page.PageParam;
import com.anti.jdbc.support.page.PageResult;
import com.anti.modular.sys.file.entity.SysFileInfo;
import com.anti.modular.sys.file.enums.FileLocationEnum;
import com.anti.modular.sys.file.enums.SysFileInfoExceptionEnum;
import com.anti.modular.sys.file.param.SysFileInfoParam;
import com.anti.modular.sys.file.result.SysFileInfoResult;
import com.anti.modular.sys.file.service.SysFileInfoService;
import com.anti.modular.sys.file.util.DownloadUtil;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * @Description TODO
 * @Author anTi
 * @Date 2021-4-7
 */
@Service
public class SysFileInfoServiceImpl implements SysFileInfoService {
    private static final Log log = Log.get();

    @Resource
    DBUtils dbUtils;
    @Resource
    private FileOperators fileOperator;
    /**
     * 默认文件存储的位置
     */
    public static final String DEFAULT_BUCKET = "defaultBucket";

    @Override
    public Long saveUploadFile(MultipartFile file) {
        // 生成文件的唯一id
//        Long fileId = UUID.fastUUID();

        // 获取文件原始名称
        String originalFilename = file.getOriginalFilename();

        // 获取文件后缀
        String fileSuffix = null;

        if (ObjectUtil.isNotEmpty(originalFilename)) {
            fileSuffix = StrUtil.subAfter(originalFilename, SymbolConstant.PERIOD, true);
        }
        // 生成文件的最终名称
//        String finalName = fileId + SymbolConstant.PERIOD + fileSuffix;
        String finalName = UUID.fastUUID() + SymbolConstant.PERIOD + fileSuffix;

        // 存储文件
        byte[] bytes;
        try {
            bytes = file.getBytes();
            fileOperator.storageFile(DEFAULT_BUCKET, finalName, bytes);
        } catch (IOException e) {
            throw new BusinessException(SysFileInfoExceptionEnum.ERROR_FILE);
        }

        // 计算文件大小kb
        long fileSizeKb = Convert.toLong(NumberUtil.div(new BigDecimal(file.getSize()), BigDecimal.valueOf(1024))
                .setScale(0, BigDecimal.ROUND_HALF_UP));

        //计算文件大小信息
        String fileSizeInfo = FileUtil.readableFileSize(file.getSize());

        // 存储文件信息
        SysFileInfo sysFileInfo = new SysFileInfo();
//        sysFileInfo.setId(fileId);
        sysFileInfo.setFileLocation(FileLocationEnum.LOCAL.getCode());
        sysFileInfo.setFileBucket(DEFAULT_BUCKET);
        sysFileInfo.setFileObjectName(finalName);
        sysFileInfo.setFileOriginName(originalFilename);
        sysFileInfo.setFileSuffix(fileSuffix);
        sysFileInfo.setFileSizeKb(fileSizeKb);
        sysFileInfo.setFileSizeInfo(fileSizeInfo);
        String key = dbUtils.insertKey(sysFileInfo).toString();
        // 返回文件id
        return Long.parseLong(key);
    }

    @Override
    public void download(SysFileInfoParam sysFileInfoParam, HttpServletResponse response) {
        // 获取文件信息结果集
        SysFileInfoResult sysFileInfoResult = this.getFileInfoResult(sysFileInfoParam.getId());
        String fileName = sysFileInfoResult.getFileOriginName();
        byte[] fileBytes = sysFileInfoResult.getFileBytes();
        DownloadUtil.download(fileName, fileBytes, response);
    }

    @Override
    public void preview(SysFileInfoParam sysFileInfoParam, HttpServletResponse response) {
        byte[] fileBytes;
        //根据文件id获取文件信息结果集
        SysFileInfoResult sysFileInfoResult = this.getFileInfoResult(sysFileInfoParam.getId());
        //获取文件后缀
        String fileSuffix = sysFileInfoResult.getFileSuffix().toLowerCase();
        //获取文件字节码
        fileBytes = sysFileInfoResult.getFileBytes();
        //如果是图片类型，则直接输出
        if (LibreOfficeUtil.isPic(fileSuffix)) {
            try {
                //设置contentType
                response.setContentType(MediaType.IMAGE_JPEG_VALUE);
                //获取outputStream
                ServletOutputStream outputStream = response.getOutputStream();
                //输出
                IoUtil.write(outputStream, true, fileBytes);
            } catch (IOException e) {
                throw new BusinessException(SysFileInfoExceptionEnum.PREVIEW_ERROR_NOT_SUPPORT);
            }

        } else if (LibreOfficeUtil.isDoc(fileSuffix)) {
            try {
                //如果是文档类型，则使用libreoffice转换为pdf或html
                InputStream inputStream = IoUtil.toStream(fileBytes);

                //获取目标contentType（word和ppt和text转成pdf，excel转成html)
                String targetContentType = LibreOfficeUtil.getTargetContentTypeBySuffix(fileSuffix);

                //设置contentType
                response.setContentType(targetContentType);

                //获取outputStream
                ServletOutputStream outputStream = response.getOutputStream();

                //转换
                LibreOfficeUtil.convertToPdf(inputStream, outputStream, fileSuffix);

                //输出
                IoUtil.write(outputStream, true, fileBytes);
            } catch (IOException e) {
                log.error(">>> 预览文件异常", e.getMessage());
                throw new BusinessException(SysFileInfoExceptionEnum.PREVIEW_ERROR_NOT_SUPPORT);

            } catch (LibreOfficeException e) {
                log.error(">>> 初始化LibreOffice失败", e.getMessage());
                throw new BusinessException(SysFileInfoExceptionEnum.PREVIEW_ERROR_LIBREOFFICE);
            }

        } else {
            //否则不支持预览（暂时）
            throw new BusinessException(SysFileInfoExceptionEnum.PREVIEW_ERROR_NOT_SUPPORT);
        }
    }

    @Override
    public PageResult page(PageParam pageParam, SysFileInfoParam sysFileInfoParam) {
        // 构造条件
        StringBuilder sb=new StringBuilder("select * from sys_file_info where 1=1 ");
        ArrayList<Object> params = CollectionUtil.newArrayList();
        // 拼接查询条件-文件存储位置（1:阿里云，2:腾讯云，3:minio，4:本地）
        if (ObjectUtil.isNotNull(sysFileInfoParam)) {
            if (ObjectUtil.isNotEmpty(sysFileInfoParam.getFileLocation())) {
                sb.append(" and file_location like ?");
                params.add("%"+sysFileInfoParam.getFileLocation()+"%");
            }

            // 拼接查询条件-文件仓库
            if (ObjectUtil.isNotEmpty(sysFileInfoParam.getFileBucket())) {
                sb.append(" and file_bucket like ?");
                params.add("%"+sysFileInfoParam.getFileBucket()+"%");
            }

            // 拼接查询条件-文件名称（上传时候的文件名）
            if (ObjectUtil.isNotEmpty(sysFileInfoParam.getFileOriginName())) {
                sb.append(" and file_origin_name like ?");
                params.add("%"+sysFileInfoParam.getFileOriginName()+"%");
            }
        }

        // 查询分页结果
        return dbUtils.query(pageParam, sb.toString(),params.toArray());
    }

    @Override
    public List<SysFileInfo> list(SysFileInfoParam sysFileInfoParam) {
        List<SysFileInfo> sysFileInfos = dbUtils.query("select * from sys_file_info", SysFileInfo.class);
        return  sysFileInfos;
    }

    @Override
    public SysFileInfo detail(SysFileInfoParam sysFileInfoParam) {
        return this.querySysFileInfo(sysFileInfoParam);

    }

    @Override
    public void delete(SysFileInfoParam sysFileInfoParam) {
        // 查询文件的信息
        SysFileInfo sysFileInfo = dbUtils.getFirst("select * from sys_file_info where id =?",SysFileInfo.class,sysFileInfoParam.getId());
        // 删除文件记录
        dbUtils.execSql("delete from sys_file_info where id =?",sysFileInfoParam.getId());
        // 删除具体文件
        this.fileOperator.deleteFile(sysFileInfo.getFileBucket(), sysFileInfo.getFileObjectName());
    }

    @Override
    public SysFileInfoResult getFileInfoResult(Long fileId) {
        byte[] fileBytes;
        // 获取文件名
        SysFileInfo sysFileInfo = dbUtils.getFirst("select * from sys_file_info where id =?",SysFileInfo.class,fileId);
        if (sysFileInfo == null) {
            throw new BusinessException(SysFileInfoExceptionEnum.NOT_EXISTED_FILE);
        }
        try {
            // 返回文件字节码
            fileBytes = fileOperator.getFileBytes(DEFAULT_BUCKET, sysFileInfo.getFileObjectName());
        } catch (Exception e) {
            log.error(">>> 获取文件流异常，请求号为：{}，具体信息为：{}", RequestNoContext.get(), e.getMessage());
            throw new BusinessException(SysFileInfoExceptionEnum.FILE_STREAM_ERROR);
        }

        SysFileInfoResult sysFileInfoResult = new SysFileInfoResult();
        BeanUtil.copyProperties(sysFileInfo, sysFileInfoResult);
        sysFileInfoResult.setFileBytes(fileBytes);

        return sysFileInfoResult;
    }

    /**
     * 获取文件信息表

     */
    private SysFileInfo querySysFileInfo(SysFileInfoParam sysFileInfoParam) {
        SysFileInfo sysFileInfo = dbUtils.getFirst("select * from sys_file_info where id =?",SysFileInfo.class,sysFileInfoParam.getId());
        if (ObjectUtil.isEmpty(sysFileInfo)) {
            throw new BusinessException(SysFileInfoExceptionEnum.NOT_EXISTED);
        }
        return sysFileInfo;
    }
}
